package com.example.gateway.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;

import org.springframework.stereotype.Component;

import org.springframework.web.server.ServerWebExchange;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;

import reactor.core.publisher.Mono;

@Component
public class LoggingGlobalFilter implements GlobalFilter, Ordered {

    private static final Logger log = LoggerFactory.getLogger(LoggingGlobalFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getURI().getPath();
        String method = exchange.getRequest().getMethod() != null ? exchange.getRequest().getMethod().name() : "UNKNOWN";

        log.info("[全局日志-请求开始] 路径：{}，方法：{}", path, method);

        long startTime = System.currentTimeMillis();

        return chain.filter(exchange)
                .doOnError(throwable ->
                        log.error("[全局日志-请求异常] 路径：{}，方法：{}，异常：{}", path, method, throwable.getMessage(), throwable)
                )
                .doFinally(signalType -> {
                    long duration = System.currentTimeMillis() - startTime;
                    Integer statusCode = exchange.getResponse().getStatusCode() != null ? exchange.getResponse().getStatusCode().value() : null;

                    if (statusCode == null) {
                        log.warn("[全局日志-请求结束] 路径：{}，方法：{}，状态码未知，耗时：{}ms，结束类型：{}", path, method, duration, signalType);
                    } else if (statusCode >= 400) {
                        log.error("[全局日志-请求结束] 路径：{}，方法：{}，状态码：{}，耗时：{}ms，结束类型：{}", path, method, statusCode, duration, signalType);
                    } else {
                        log.info("[全局日志-请求结束] 路径：{}，方法：{}，状态码：{}，耗时：{}ms，结束类型：{}", path, method, statusCode, duration, signalType);
                    }
                });
    }

    @Override
    public int getOrder() {
        return -1; // 优先级高，确保先执行
    }
}
